package demo.security;

import org.springframework.boot.autoconfigure.security.oauth2.client.EnableOAuth2Sso;
import org.springframework.boot.autoconfigure.security.oauth2.resource.UserInfoRestTemplateFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.oauth2.client.OAuth2ClientContext;
import org.springframework.security.oauth2.client.OAuth2RestOperations;
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
import org.springframework.security.oauth2.client.filter.state.StateKeyGenerator;
import org.springframework.security.oauth2.client.resource.OAuth2AccessDeniedException;
import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails;
import org.springframework.security.oauth2.client.resource.UserApprovalRequiredException;
import org.springframework.security.oauth2.client.resource.UserRedirectRequiredException;
import org.springframework.security.oauth2.client.token.AccessTokenRequest;
import org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeAccessTokenProvider;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.util.RandomValueStringGenerator;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Configuration
@EnableOAuth2Sso
public class SsoConfiguration extends WebSecurityConfigurerAdapter {
	
//	private static final String DEFAULT_LOGIN_FORM_URL = "/authenticate"; //must be the same as registered redirect_uri in OAuth2 server
	
	@Override
	protected void configure(HttpSecurity http) throws Exception {

		http.authorizeRequests().antMatchers("/**").authenticated()
//				.antMatchers("/customer/**","/account/**").authenticated()
//			.and()
//				.authorizeRequests().anyRequest().permitAll()
				.and().formLogin().and().httpBasic();

//		http.exceptionHandling().authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint(DEFAULT_LOGIN_FORM_URL));
//		http.addFilterBefore(ssoFilter() , BasicAuthenticationFilter.class);
		
		OAuth2RestTemplate restTemplate = this.getApplicationContext().getBean(UserInfoRestTemplateFactory.class).getUserInfoRestTemplate();
		restTemplate.setAccessTokenProvider(tokenProvider());
	}
	
	private AuthorizationCodeAccessTokenProvider tokenProvider() {
		
		AuthorizationCodeAccessTokenProvider tokenProvider = new AuthorizationCodeAccessTokenProvider() {
			@Override
			public String obtainAuthorizationCode(OAuth2ProtectedResourceDetails details, AccessTokenRequest request)
					throws UserRedirectRequiredException, UserApprovalRequiredException, AccessDeniedException,
					OAuth2AccessDeniedException {

				String code = super.obtainAuthorizationCode(details, request);

				log.debug("***obtainAuthorizationCode(...), code={}", code);

				return code;
			}

			@Override
			public OAuth2AccessToken obtainAccessToken(OAuth2ProtectedResourceDetails details,
					AccessTokenRequest request) throws UserRedirectRequiredException, UserApprovalRequiredException,
					AccessDeniedException, OAuth2AccessDeniedException {

				OAuth2AccessToken token = super.obtainAccessToken(details, request);

				log.debug("***obtainAccessToken(...), token={}", token);

				return token;
			}
		};

		tokenProvider.setStateKeyGenerator(new StateKeyGenerator() {

			private RandomValueStringGenerator generator = new RandomValueStringGenerator(16);

			@Override
			public String generateKey(OAuth2ProtectedResourceDetails resource) {

				String token = generator.generate();

				log.debug("***generateKey: {}", token);

				return token;
			}
		});

		return tokenProvider;
	}

//	private OAuth2ClientAuthenticationProcessingFilter ssoFilter() {
//
//		OAuth2ProtectedResourceDetails resource = this.getApplicationContext().getBean(OAuth2ProtectedResourceDetails.class);
//		OAuth2ClientContext client = this.getApplicationContext().getBean(OAuth2ClientContext.class);
//
//		OAuth2RestTemplate restTemplate = new OAuth2RestTemplate(resource,client);
//
//		restTemplate.setAccessTokenProvider(tokenProvider());
//		
//		ResourceServerTokenServices tokenServices = this.getApplicationContext().getBean(ResourceServerTokenServices.class);
//		
//		OAuth2ClientAuthenticationProcessingFilter filter = new OAuth2ClientAuthenticationProcessingFilter(DEFAULT_LOGIN_FORM_URL);
//		filter.setRestTemplate(restTemplate);
//		filter.setTokenServices(tokenServices);
//		filter.setApplicationEventPublisher(this.getApplicationContext());
//		return filter;
//	}
}
